<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <p ref="one">{{count}}</p>
        <p>
            <button @click="addCount">count++</button>
        </p>
    </div>
</body>
<script type="module">
    // 整体载入  => 查看模块内暴露的变量和方法
    import * as Vue from "../js/vue.esm-browser.js";
    console.log(Vue);

    // 按需引入
    import { createApp, ref, reactive, readonly, computed, watch,getCurrentInstance } from "../js/vue.esm-browser.js";


    // 组合式写法 可以理解为是选项式语法的优化, 但是最终还是会被解析成选项式语法
    // 在 setup() 函数中返回的对象会暴露给模板和组件实例。其他的选项也可以通过组件实例来获取 setup() 暴露的属性
    let app = createApp({
        setup() {

            /* 
                watch()​
                    侦听一个或多个响应式数据源，并在数据源变化时调用所给的回调函数(执行副作用操作)。

                用法
                watch(source,callback,option)   侦听一个数据源
                    source  监听的数据(ref对象 计算属性  getter函数)
                    callback   数据源变化时调用所给的回调函数
                    option    监听数据时的配置项
                        deep 是否开启深度监听 (true/false默认)
                        immediate  是否在页面初始化阶段立即执行一次  (true/false默认)
                        once  只监听一次,就会被移出
                        flush  回调函数执行的时机
                            sync 数据改变后,立即执行
                            pre 数据改变后,视图更新前执行(默认)
                            post  数据改变,视图更新后执行 => 可以理解为包裹了 $nextTick

                watch([source,source,source],callback,option)   侦听多个数据源(只要数组中的某一个数据源改变,都会触发回调函数)
                    [source,source,source]  监听的数据的数组
                    callback   数据源变化时调用所给的回调函数


                注意:
                    watch监听ref对象是默认是浅层的,不管ref对象中存储的是基本数据类型该是引用数据类型,都无所谓 => 只关注.value值是否改变
                    watch监听proxy代理对象是默认是深层的,不仅可以监听proxy代理对象根属性的属性值是否改变,如果听proxy代理对象根属性的属性值是一个对象,也可以监听该对象的改变


                
            
            */
            let count = ref(1);
            const addCount = () => {
                count.value++;
            }

            let one = ref();  // 对应ref名获取元素(变量名和ref名保持一致) => 返回ref对象
            // console.log(one.value); // 直接打印有问题, 页面还未渲染 返回undefined

            // let cur = getCurrentInstance(); // 获取当前vue实例
            // let ctx = cur.ctx;  // 获取当前vue实例proxy代理
            // watch(count,function(newVal,oldVal){
            //     console.log("count改变了:pre",newVal,oldVal);

            //     // 数据改变之后 视图并不会立即更新
            //     // console.log("p的内容",one.value.innerText);

            //     ctx.$nextTick(()=>{  // 等视图更新后执行
            //         console.log("p的内容",one.value.innerText);
            //     })
            // },{
            //     flush:"pre", // 默认
            // })

            // 等价于上述写法
            // watch(count,function(newVal,oldVal){
            //     console.log("count改变了:pre",newVal,oldVal);
            //     // 数据改变之后 视图并不会立即更新
            //     console.log("p的内容",one.value.innerText);

            // },{
            //     flush:"post", //等视图更新后执行
            // })


           
          

            watch(count,function(newVal,oldVal){
                console.log("count改变了:sync",newVal,oldVal);
            },{
                flush:"sync", //等视图更新后执行
            })

            watch(count,function(newVal,oldVal){
                console.log("count改变了:pre",newVal,oldVal);
            },{
                flush:"pre", //等视图更新后执行(默认)
            })
         
            watch(count,function(newVal,oldVal){
                console.log("count改变了:post",newVal,oldVal);
            },{
                flush:"post", //等视图更新后执行
            })


           

            return {
                one,
                count,
                addCount,
            }
        },
        mounted() {
            console.log("mounted", this);

            /* 
                this => 当前vue实例的Proxy代理对象(模拟)
                Proxy => {   // 写法只是方便理解
                    get a(){
                        return a.value;
                    }
                    set a(val){
                        a.value = val;
                    }
                }

            
            
            */
        },
    })

    app.mount("#app");
</script>

</html>